﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace THO7AlgoritmTimerApplication
{
    class OCR
    {
        private Bitmap TwoColor(Bitmap sourceImage)
        {
            Bitmap returnImage = new Bitmap(sourceImage);
            Rectangle rect = new Rectangle(0, 0, returnImage.Width, returnImage.Height);
            BitmapData myBmpData = returnImage.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            IntPtr ptr = myBmpData.Scan0;
            int numBytes = returnImage.Width * returnImage.Height * 3;
            byte[] rgbValues = new byte[numBytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);
            for (int i = 0; i < rgbValues.Length; i += 3)
            {
                if (rgbValues[i] < 50 || rgbValues[i+1] < 50 || rgbValues[i+2] < 50)
                {
                    rgbValues[i] = 0;
                    rgbValues[i + 1] = 0;
                    rgbValues[i + 2] = 0;
                }
                else
                {
                    rgbValues[i] = 255;
                    rgbValues[i + 1] = 255;
                    rgbValues[i + 2] = 255;
                }
            }
            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);
            returnImage.UnlockBits(myBmpData);
            return returnImage;
        }
        private Bitmap VerwijderWit(Bitmap sourceImage)
        {
            BitmapData bmpdata = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            IntPtr ptr = bmpdata.Scan0;
            int regellengte = Math.Abs(bmpdata.Stride);
            int bytes = regellengte * sourceImage.Height;
            byte[] rgbValues = new byte[bytes];
            byte[] output = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
            int new_width = 0;
            int new_height = 0;
            for (int regelnummer = 0; regelnummer < sourceImage.Height - 1; regelnummer++) {
                for (int convolutie = 0; convolutie < regellengte; convolutie += 3) {
                    int pixel = regelnummer * regellengte + convolutie;
                    if (rgbValues[pixel] < 10 && rgbValues[pixel + 1] < 10 && rgbValues[pixel + 2] < 10) {
                        for (int c = 0; c < regellengte; c += 3) {
                            int p = regelnummer * regellengte + c;
                            int new_pixel = new_height * regellengte + c;
                            output[new_pixel] = rgbValues[p];
                            output[new_pixel + 1] = rgbValues[p + 1];
                            output[new_pixel + 2] = rgbValues[p + 2];
                        }
                        new_height++;
                        break;
                    }
                }
            }
            new_width = sourceImage.Width;
            if (new_height == 0)
            {
                new_height = 1;
            }
            Bitmap dest = new Bitmap(new_width, new_height);
            BitmapData bmpdata1 = dest.LockBits(new Rectangle(0, 0, new_width, new_height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
            IntPtr ptr1 = bmpdata1.Scan0;
            System.Runtime.InteropServices.Marshal.Copy(output, 0, ptr1, (new_height * regellengte));
            sourceImage.UnlockBits(bmpdata);
            dest.UnlockBits(bmpdata1);
            return dest;
        }
        //afbeelding kleiner maken totdat hij echt tegen de letter aan zit
        //middelste van de lijnen nemen zodat er een dunne lijn over blijft
        //vervolgens deze methodes erover heen doen
        //opdelen in veel meer vlakken en dan niet kijken hoeveel pixels er goed staan per vlak maar hoeveel vlakken goed zijn.
        //kijken hoeveel vlakken overeen komen.
        private const int verdeling = 5;
        public String regonize(Bitmap sourceImage)
        {
            //bestand uitlezen en naar een buffer schrijven.
            StreamReader reader = new StreamReader("OCR.txt");
            List<String> characters = new List<String>();
            //lees het bestand uit
            String s = "";
            while ((s = reader.ReadLine()) != null)
            {
                characters.Add(s);
            }
            reader.Close();
            //plaatje bekijken
            Bitmap returnImage = new Bitmap(sourceImage);
            VisionAlgorithm contrast = new contrast_add("");
            contrast.setMarge(100);
            returnImage = contrast.DoAlgorithm(returnImage);
            VisionAlgorithm c = new Cropwhite("");
            returnImage = c.DoAlgorithm(returnImage);
            returnImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
            returnImage = contrast.DoAlgorithm(returnImage);
            returnImage = c.DoAlgorithm(returnImage);
            returnImage.RotateFlip(RotateFlipType.Rotate270FlipNone);

            Rectangle rect = new Rectangle(0, 0, returnImage.Width, returnImage.Height);
            BitmapData myBmpData = returnImage.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            IntPtr ptr = myBmpData.Scan0;
            int numBytes = returnImage.Width * returnImage.Height * 3;
            byte[] rgbValues = new byte[numBytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);

            int xGroote = returnImage.Width / verdeling + 1;
            //is niet goed want het delen door dat wordt afgerond dus ik heb +1 gedaan zodat hij niet vastloopt als hij hoger blijkt
            int yGroote = returnImage.Height / verdeling + 1;
            //deel het plaatje op in negen stukken
            int[] zwart = new int[verdeling * verdeling];
            int pixels = xGroote * yGroote;
            for (int i = 0; i < (rgbValues.Length/3); i++)
            {
                int xpositie = (i % returnImage.Width) / xGroote;
                int ypositie = ((i - (i % returnImage.Width)) / returnImage.Width) / yGroote;
                if (rgbValues[i*3] < 100)
                {
                    zwart[(ypositie * verdeling) + xpositie]++;
                }
            }
            //kijk per stuk hoeveel procent zwart is.
            int[] procenten = new int[verdeling * verdeling];
            for (int i = 0; i < (verdeling * verdeling); i++)
            {
                procenten[i] = ((zwart[i]*1000) / pixels);
            }

            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);
            returnImage.UnlockBits(myBmpData);
            //kijk bij wie hij het dichtst in de buurt komt
            int hoogsteGoed = 0;
            String juiste = "?";
            for (int i = 0; i < characters.Count; i++)
            {
                //haal eerst de waardes uit de string van het tekst document
                int[] f = new int[verdeling * verdeling];
                string[] words = characters[i].Split(' ');
                for (int j = 1; j < (verdeling * verdeling) + 1; j++)
                {
                    f[j - 1] = int.Parse(words[j]);
                }
                //bekijk hoeveel vlakken overeen komen
                //eerst zat ik afwijkingen bij elkaar op te tellen maar dat komt op hetzelfde neer als het hele de afwijking bekijken
                int goed = 0;
                for (int j = 0; j < (verdeling * verdeling); j++)
                {
                    int temp = procenten[j] - f[j];
                    if (temp < 5 && temp > -5)
                    {
                        goed += 1;
                    }
                }
                if (goed > hoogsteGoed)
                {
                    hoogsteGoed = goed;
                    juiste = words[0];
                }
            }
            return juiste + " " + hoogsteGoed;
        }

        public Bitmap learn(Bitmap sourceImage,String character, out String output)
        {
            //ik ga ervan uit dat de letters die vergeleken moeten worden net zo staan als de leer afbeeldingen
            //dus als de leerafbeeldingen scheef staan dan kan hij alleen scheefe letters herkennen
            //bestand uitlezen en naar een buffer schrijven.
            StreamReader reader = new StreamReader("OCR.txt");
            List<String> characters = new List<String>();
            //lees het bestand uit
            String s = "";
            while ((s = reader.ReadLine()) != null)
            {
                characters.Add(s);
            }
            reader.Close();

            //plaatje bekijken
            Bitmap returnImage = new Bitmap(sourceImage);
            VisionAlgorithm contrast = new contrast_add("");
            contrast.setMarge(100);
            returnImage = contrast.DoAlgorithm(returnImage);
            VisionAlgorithm c = new Cropwhite("");
            returnImage = c.DoAlgorithm(returnImage);
            returnImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
            returnImage = contrast.DoAlgorithm(returnImage);
            returnImage = c.DoAlgorithm(returnImage);
            returnImage.RotateFlip(RotateFlipType.Rotate270FlipNone);


            Rectangle rect = new Rectangle(0, 0, returnImage.Width, returnImage.Height);
            BitmapData myBmpData = returnImage.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            IntPtr ptr = myBmpData.Scan0;
            int numBytes = returnImage.Width * returnImage.Height * 3;
            byte[] rgbValues = new byte[numBytes];
            System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, numBytes);

            int xGroote = returnImage.Width / verdeling + 1;
            //is niet goed want het delen door dat wordt afgerond dus ik heb +1 gedaan zodat hij niet vastloopt als hij hoger blijkt
            int yGroote = returnImage.Height / verdeling + 1;
            //deel het plaatje op in meerdere stukken
            int[] zwart = new int[verdeling * verdeling];
            int pixels = xGroote * yGroote;
            for (int i = 0; i < (rgbValues.Length/3); i++)
            {
                int xpositie = (i % returnImage.Width) / xGroote;
                int ypositie = ((i - (i % returnImage.Width)) / returnImage.Width) / yGroote;
                if (rgbValues[i*3] < 100)
                {
                    zwart[(ypositie * verdeling) + xpositie]++;
                }
            }
            //kijk per stuk hoeveel procent zwart is.
            int[] procenten = new int[verdeling * verdeling];
            for (int i = 0; i < (verdeling * verdeling); i++)
            {
                procenten[i] = ((zwart[i]*1000) / pixels);
            }

            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, numBytes);
            returnImage.UnlockBits(myBmpData);

            //kijk of er al een is die dezelfde letter heeft.
            Boolean gevonden = false;
            for (int i = 0; i < characters.Count; i++)
            {
                if (characters[i][0] == character[0])
                {
                    //combineer de waardes
                    //haal eerst de waardes uit de string van het tekst document
                    int[] f = new int[verdeling * verdeling + 1];
                    string[] words = characters[i].Split(' ');
                    for (int j = 1; j < (verdeling * verdeling) + 2; j++)
                    {
                        f[j-1] = int.Parse(words[j]);
                    }
                    String temp = character;
                    for (int j = 0; j < (verdeling * verdeling); j++)
                    {
                        f[j] = ((f[j] * f[verdeling * verdeling]) + procenten[j]) / (f[verdeling * verdeling] + 1);
                        temp += " " + f[j];
                    }
                    f[verdeling * verdeling]++;
                    temp += " " + f[verdeling * verdeling];
                    characters[i] = temp;
                    gevonden = true;
                    break;
                }
            }
            if (!gevonden)
            {
                String waardes = character;
                for (int j = 0; j < (verdeling * verdeling); j++)
                {
                    waardes += " " + procenten[j];
                }
                waardes += " " + 1;
                characters.Add(waardes);
            }
            //schrijf nu alle waardes terug naar de tekst file
            StreamWriter writer = new StreamWriter("OCR.txt");
            for (int i = 0; i < characters.Count; i++)
            {
                writer.WriteLine(characters[i]);
            }
            writer.Close();
            output = regonize(sourceImage);
            return returnImage;
        }
    }
}
